package com.dss.auto_deploy.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dss.auto_deploy.config.WebsocketEndPoint;
import com.dss.auto_deploy.constants.AutoConstants;
import com.dss.auto_deploy.domain.*;
import com.dss.auto_deploy.dto.AdmDbAddDto;
import com.dss.auto_deploy.dto.AdmDbPageDto;
import com.dss.auto_deploy.dto.AdmDbUpdateDto;
import com.dss.auto_deploy.dto.WsSendDto;
import com.dss.auto_deploy.mapper.AdmDbMapper;
import com.dss.auto_deploy.mapper.AdmDockerMapper;
import com.dss.auto_deploy.mapper.AdmProjectMapper;
import com.dss.auto_deploy.service.IAdmDbService;
import com.dss.auto_deploy.service.IAdmDockerService;
import com.dss.auto_deploy.service.IServerService;
import com.dss.auto_deploy.util.*;
import com.dss.auto_deploy.vo.AdmDbVo;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.model.Container;
import com.jcraft.jsch.Session;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.jdbc.ScriptRunner;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.sql.*;
import java.util.Date;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;


/**
 * @author dongshoushan
 * @Description:数据库Service实现类
 * @date 2022-10-29 13:00:17
 */
@Service
@Slf4j
@RequiredArgsConstructor(onConstructor = @_(@Autowired))
public class AdmDbServiceImpl extends ServiceImpl<AdmDbMapper, AdmDb> implements IAdmDbService {

    /**
     * 数据库Mapper
     */
    private final AdmDbMapper admDbMapper;
    private final ThreadPoolTaskExecutor threadPoolTaskExecutor;
    private final RemoteSshUtil remoteSshUtil;
    private final AdmDockerMapper admDockerMapper;
    private final AdmProjectMapper admProjectMapper;
    private final IServerService serverService;
    private final IAdmDockerService admDockerService;
    private final WebsocketEndPoint websocketEndPoint;
    private final CacheUtils cacheUtils;
    private final DockerUtil dockerUtil;
    private final String baseMysqlLocalPath = System.getProperty("user.dir") + "/temp/config/mysql";
    private final String baseRedisLocalPath = System.getProperty("user.dir") + "/temp/config/redis";

    /**
     * 新增数据库
     *
     * @param admDbAddDto
     * @return Long
     */
    @Override
    public int insert(AdmDbAddDto admDbAddDto) {
        AdmDb admDb = BeanUtils.copy(admDbAddDto, AdmDb.class);
        List<AdmDocker> dockerList = admDockerService.getAll();
        AdmDocker admDocker = dockerList.stream().filter(s -> s.getId().equals(admDbAddDto.getDockerId())).findFirst().orElse(null);
        admDb.setServerId(admDocker.getServerId());
        int insert = admDbMapper.insert(admDb);
        if (insert == 1) {
            log.info("新增成功{}", JacksonUtils.toString(admDb));
        }
        return insert;
    }


    /**
     * 修改数据库
     *
     * @param admDbUpdateDto
     * @return Long
     */
    @Override
    public int update(AdmDbUpdateDto admDbUpdateDto) {
        AdmDb dbOld = admDbMapper.selectById(admDbUpdateDto.getId());
        AdmDb admDb = BeanUtils.copy(admDbUpdateDto, AdmDb.class);
        admDb.setServerId(dbOld.getServerId());
        if (!dbOld.getPassword().equals(admDbUpdateDto.getPassword())) {
            switch (dbOld.getDbType()) {
                case "mysql":
                    try {
                        updateMysqlPassword(dbOld, admDb);
                    } catch (Exception e) {
                        e.printStackTrace();
                        throw new ServiceException("修改mysql密码失败");
                    }
                    break;
                case "redis":

                    break;
                case "mongo":

                    break;
            }
        }
        int number = admDbMapper.updateById(admDb);
        admDb = this.getById(dbOld.getId());
        if (number == 1) {
            log.info("修改成功{}", JacksonUtils.toString(admDb));
        }
        return number;
    }


    /**
     * 批量删除数据库
     *
     * @param ids
     * @return Long
     */
    @Override
    public void deleteBatch(Long[] ids) {
        this.removeByIds(Arrays.asList(ids));
    }

    /**
     * 数据库分页查询
     *
     * @param pageDto
     * @return List<AdmDb>
     */
    @Override
    public Page<AdmDbVo> list(AdmDbPageDto pageDto) throws InterruptedException {
        Page<AdmDb> tablesPage = new Page<>(pageDto.getPage(), pageDto.getLimit());
        QueryWrapper<AdmDb> queryWrapper = Wrappers.query();
        if (StringUtils.isNotEmpty(pageDto.getContent())) {
            queryWrapper.like("name", pageDto.getContent());
        }
        queryWrapper.eq("db_type", pageDto.getDbType()).orderByAsc("db_type").orderByAsc("server_id");
        Page<AdmDb> pageSelectResult = admDbMapper.selectPage(tablesPage, queryWrapper);
        List<AdmDb> records = pageSelectResult.getRecords();
        List<AdmDbVo> voList = convertToVo(records);
        Page<AdmDbVo> page = new Page<>();
        page.setRecords(voList);
        page.setTotal(pageSelectResult.getTotal());
        page.setSize(pageSelectResult.getSize());
        return page;
    }

    public List<AdmDbVo> convertToVo(List<AdmDb> list) throws InterruptedException {
        if (list == null || list.isEmpty()) {
            return new ArrayList<>();
        }
        List<AdmDbVo> admDockerVos = BeanUtils.copyList(list, AdmDbVo.class);
        List<Long> dockerIds = list.stream().map(AdmDb::getDockerId).collect(Collectors.toList());
        List<Server> serverList = serverService.getAll();
        List<AdmDocker> dockerList = admDockerService.getAll().stream().filter(s->dockerIds.contains(s.getId())).collect(Collectors.toList());
        Map<String, List<Container>> containerMap = admDockerService.getContainerMap(dockerList);
        admDockerVos.forEach(vo -> {
            Server serverVo = serverList.stream().filter(s -> s.getId().equals(vo.getServerId())).findFirst().orElse(null);
            vo.setIp(serverVo.getIp());
            AdmDocker admDocker = dockerList.stream().filter(s -> s.getServerId().equals(vo.getServerId())).findFirst().orElse(null);
            if (admDocker == null) {
                vo.setStateName("未绑定docker");
            }else if (vo.getContainerId() == null){
                vo.setStateName("未安装");
            }else {
                List<Container> containers = containerMap.get("AdmDockerVo" + admDocker.getId());
                Container container = containers.stream().filter(s -> s.getId().equals(vo.getContainerId())).findFirst().orElse(null);
                if (container == null) {
                    vo.setStateName("容器未创建");
                } else {
                    vo.setStateName(container.getState());
                }
            }
        });
        return admDockerVos;
    }

    @Override
    public void installMysql(String ids, String tempPath, MultipartFile file) {
        long fileSize = file.getSize();
        String[] split = ids.split(",");
        CountDownLatch mainLatch = new CountDownLatch(split.length);
        for (String id : split) {
            threadPoolTaskExecutor.execute(() -> {
                //上传包
                try {
                    AdmDb admDb = admDbMapper.selectById(id);
                    if (admDb.getDockerId() == null) {
                        return;
                    }
                    AdmDocker admDocker = admDockerMapper.selectById(admDb.getDockerId());
                    Server serverDocker = serverService.getServerById(admDb.getServerId());
                    Session session = remoteSshUtil.connect(serverDocker);
                    System.out.println("开始上传mysql镜像文件");
                    //关闭防火墙
                    remoteSshUtil.exec(AutoConstants.DISABLE_FIREWALLD, session);
                    remoteSshUtil.exec(AutoConstants.STOP_FIREWALLD, session);
                    remoteSshUtil.exec(AutoConstants.AUTHORIZATION_FOLDER + tempPath, session);
                    CountDownLatch mainLatch2 = new CountDownLatch(1);
                    threadPoolTaskExecutor.execute(() -> {
                        try {
                            remoteSshUtil.putFile(session, file, tempPath, fileSize, Long.parseLong(id), "dbInstall", serverDocker.getIp());
                        } catch (Exception e) {
                            throw new ServiceException(e.getMessage());
                        } finally {
                            mainLatch2.countDown();
                        }
                    });
                    mainLatch2.await();
                    sendMsg("installing", file.getOriginalFilename(), Long.parseLong(id));
                    String mountPath = admDb.getMountPath();
                    String configLocalPath = baseMysqlLocalPath + "/" + admDb.getId() + "/my.cnf";
                    remoteSshUtil.exec(StringUtils.format("mkdir -p {} {}/conf {}/logs {}/data", mountPath, mountPath, mountPath, mountPath), session);
                    FileUtils.generateFileByTemplate("mysql.ftl", configLocalPath, baseMysqlLocalPath + "/" + admDb.getId(), null);
                    remoteSshUtil.putFile(session, configLocalPath, mountPath + "/conf");
                    remoteSshUtil.exec(AutoConstants.AUTHORIZATION_FOLDER + mountPath, session);
                    DockerClient dockerClient = dockerUtil.getDockerClientByDocker(SpringUtils.getBean(AdmDockerServiceImpl.class).convertToVo(admDocker));
                    dockerUtil.delContainer(dockerClient, "mysql");
                    dockerUtil.close(dockerClient);
                    sendMsg("loading", file.getOriginalFilename(), Long.parseLong(id));
                    //加载到镜像
                    remoteSshUtil.exec(StringUtils.format("docker load -i {}/{}", tempPath, file.getOriginalFilename()), session);
                    //安装mysql
                    String info = StringUtils.format("docker run --restart=always  --privileged=true  \\\n" +
                            "-p {}:3306 \\\n" +
                            "-v {}/data/:/var/lib/mysql \\\n" +
                            "-v {}/logs/:/var/log/mysql \\\n" +
                            "-v {}/conf:/etc/mysql/conf.d \\\n" +
                            "--name mysql \\\n" +
                            "-v /etc/localtime:/etc/localtime \\\n" +
                            "-e MYSQL_ROOT_PASSWORD={} -d mysql:latest", admDb.getPort(), mountPath, mountPath, mountPath, admDb.getPassword());
                    System.out.println(info);
                    String exec = remoteSshUtil.exec(info, session);
                    System.out.println(exec);
                    admDb.setContainerId(exec.replace("\n", ""));
                    admDb.setInstallTime(new Date());
                    this.updateById(admDb);
                    sendMsg("starting", file.getOriginalFilename(), Long.parseLong(id));
                    Thread.sleep(100 * 1000);
                    if (!"root".equals(admDb.getUsername())) {
                        creatMysqlUser(admDb);
                    }
                    sendMsg("complete", file.getOriginalFilename(), Long.parseLong(id));
                    remoteSshUtil.close(session);
                } catch (Exception e) {
                    e.printStackTrace();
                    alertFailMsg(e.getMessage());
                } finally {
                    mainLatch.countDown();
                }
            });
        }
        try {
            mainLatch.await();
            System.out.println("mysql全部安装完毕");
            alertSuccessMsg("completeAll");
        } catch (InterruptedException e) {
            log.error(e.getMessage());
        }
    }

    @Override
    public void installPostgres(String ids, String tempPath, MultipartFile file) throws InterruptedException {
        long fileSize = file.getSize();
        String[] split = ids.split(",");
        CountDownLatch mainLatch = new CountDownLatch(split.length);
        for (String id : split) {
            threadPoolTaskExecutor.execute(() -> {
                //上传包
                try {
                    AdmDb admDb = admDbMapper.selectById(id);
                    if (admDb.getDockerId() == null) {
                        return;
                    }
                    AdmDocker admDocker = admDockerMapper.selectById(admDb.getDockerId());
                    Server serverDocker = serverService.getServerById(admDb.getServerId());
                    Session session = remoteSshUtil.connect(serverDocker);
                    System.out.println("开始上传postgres镜像文件");
                    //关闭防火墙
                    remoteSshUtil.exec(AutoConstants.DISABLE_FIREWALLD, session);
                    remoteSshUtil.exec(AutoConstants.STOP_FIREWALLD, session);
                    remoteSshUtil.exec(AutoConstants.AUTHORIZATION_FOLDER + tempPath, session);
                    CountDownLatch mainLatch2 = new CountDownLatch(1);
                    threadPoolTaskExecutor.execute(() -> {
                        try {
                            remoteSshUtil.putFile(session, file, tempPath, fileSize, Long.parseLong(id), "dbInstall", serverDocker.getIp());
                        } catch (Exception e) {
                            throw new ServiceException(e.getMessage());
                        } finally {
                            mainLatch2.countDown();
                        }
                    });
                    mainLatch2.await();
                    sendMsg("installing", file.getOriginalFilename(), Long.parseLong(id));
                    String mountPath = admDb.getMountPath();
                    String configLocalPath = baseMysqlLocalPath + "/" + admDb.getId() + "/my.cnf";
                    remoteSshUtil.exec(StringUtils.format("mkdir -p {} {}/conf {}/logs {}/data", mountPath, mountPath, mountPath, mountPath), session);
                    FileUtils.generateFileByTemplate("mysql.ftl", configLocalPath, baseMysqlLocalPath + "/" + admDb.getId(), null);
                    remoteSshUtil.putFile(session, configLocalPath, mountPath + "/conf");
                    remoteSshUtil.exec(AutoConstants.AUTHORIZATION_FOLDER + mountPath, session);
                    DockerClient dockerClient = dockerUtil.getDockerClientByDocker(SpringUtils.getBean(AdmDockerServiceImpl.class).convertToVo(admDocker));
                    dockerUtil.delContainer(dockerClient, "postgres");
                    dockerUtil.close(dockerClient);
                    sendMsg("loading", file.getOriginalFilename(), Long.parseLong(id));
                    //加载到镜像
                    remoteSshUtil.exec(StringUtils.format("docker load -i {}/{}", tempPath, file.getOriginalFilename()), session);
                    //安装mysql
                    String info = StringUtils.format("docker run --name postgres \\\n" +
                            "--privileged=true \\\n" +
                            "--restart=always \\\n" +
                            "-p {}:5432 \\\n" +
                            "-e POSTGRES_PASSWORD={} \\\n" +
                            "-v /etc/localtime:/etc/localtime \\\n" +
                            "-v {}/logs:/var/log/postgresql \\\n" +
                            "-v {}/data:/var/lib/postgresql/data -d postgres",admDb.getPort(),admDb.getPassword(), mountPath, mountPath);
                    System.out.println(info);
                    String exec = remoteSshUtil.exec(info, session);
                    System.out.println(exec);
                    admDb.setContainerId(exec.replace("\n", ""));
                    admDb.setInstallTime(new Date());
                    this.updateById(admDb);
                    sendMsg("starting", file.getOriginalFilename(), Long.parseLong(id));
                    Thread.sleep(100 * 1000);
                    if (!"postgres".equals(admDb.getUsername())) {
                        creatPostgresUser(admDb);
                    }
                    sendMsg("complete", file.getOriginalFilename(), Long.parseLong(id));
                    remoteSshUtil.close(session);
                } catch (Exception e) {
                    e.printStackTrace();
                    alertFailMsg(e.getMessage());
                } finally {
                    mainLatch.countDown();
                }
            });
        }
        try {
            mainLatch.await();
            System.out.println("postgres全部安装完毕");
            alertSuccessMsg("completeAll");
        } catch (InterruptedException e) {
            log.error(e.getMessage());
        }
    }

    @Override
    public void installMongo(String ids, String tempPath, MultipartFile mongoFile, MultipartFile mongoclientFile, String clientMountPath) {
        long mongoFileSize = mongoFile.getSize();
        long mongoclientFileSize = mongoclientFile.getSize();
        String[] split = ids.split(",");
        CountDownLatch mainLatch = new CountDownLatch(split.length);
        for (String id : split) {
            threadPoolTaskExecutor.execute(() -> {
                //上传包
                try {
                    AdmDb admDb = admDbMapper.selectById(id);
                    if (admDb.getDockerId() == null) {
                        return;
                    }
                    AdmDocker admDocker = admDockerMapper.selectById(admDb.getDockerId());
                    Server serverDocker = serverService.getServerById(admDb.getServerId());
                    Session session = remoteSshUtil.connect(serverDocker);
                    System.out.println("开始上传mongo镜像文件");
                    //关闭防火墙
                    remoteSshUtil.exec(AutoConstants.DISABLE_FIREWALLD, session);
                    remoteSshUtil.exec(AutoConstants.STOP_FIREWALLD, session);
                    remoteSshUtil.exec(AutoConstants.AUTHORIZATION_FOLDER + tempPath, session);
                    CountDownLatch mainLatch2 = new CountDownLatch(2);
                    threadPoolTaskExecutor.execute(() -> {
                        try {
                            remoteSshUtil.putFile(session, mongoFile, tempPath, mongoFileSize, Long.parseLong(id), "dbInstall", serverDocker.getIp());
                        } catch (Exception e) {
                            throw new ServiceException(e.getMessage());
                        } finally {
                            mainLatch2.countDown();
                        }
                    });
                    threadPoolTaskExecutor.execute(() -> {
                        try {
                            remoteSshUtil.putFile(session, mongoclientFile, tempPath, mongoclientFileSize, Long.parseLong(id), "dbInstall", serverDocker.getIp());
                        } catch (Exception e) {
                            throw new ServiceException(e.getMessage());
                        } finally {
                            mainLatch2.countDown();
                        }
                    });
                    mainLatch2.await();
                    sendMsg("installing", mongoFile.getOriginalFilename(), Long.parseLong(id));
                    sendMsg("installing", mongoclientFile.getOriginalFilename(), Long.parseLong(id));
                    String mountPath = admDb.getMountPath();
                    remoteSshUtil.exec(StringUtils.format("mkdir -p {}", mountPath), session);
                    DockerClient dockerClient = dockerUtil.getDockerClientByDocker(SpringUtils.getBean(AdmDockerServiceImpl.class).convertToVo(admDocker));
                    dockerUtil.delContainer(dockerClient, "mongo");
                    dockerUtil.close(dockerClient);
                    sendMsg("loading", mongoFile.getOriginalFilename(), Long.parseLong(id));
                    sendMsg("loading", mongoclientFile.getOriginalFilename(), Long.parseLong(id));
                    //加载到镜像
                    String exec1 = remoteSshUtil.exec(StringUtils.format("docker load -i {}/{}", tempPath, mongoFile.getOriginalFilename()), session);
                    remoteSshUtil.exec(StringUtils.format("docker load -i {}/{}", tempPath, mongoclientFile.getOriginalFilename()), session);
                    String imageFullName = exec1.replace("Loaded image: ", "").trim();
                    //安装
                    String info = StringUtils.format("docker run --restart=always -d --name mongodb  -v {}:/data/db --network=host \\\n" +
                            "-v /etc/localtime:/etc/localtime \\\n" +
                            "-e MONGO_INITDB_ROOT_USERNAME={} \\\n" +
                            "-e MONGO_INITDB_ROOT_PASSWORD={} --privileged=true {}", mountPath, admDb.getUsername(), admDb.getPassword(), imageFullName);
                    System.out.println(info);
                    String exec = remoteSshUtil.exec(info, session);
                    Thread.sleep(3000);
                    String info2 = StringUtils.format("docker run --restart=always -d  --name mongoclient " +
                                    "-e MONGO_URL=\"mongodb://{}:{}@{}:{}/admin\" \\\n" +
                                    "-p 3000:3000 -v /etc/localtime:/etc/localtime  -v {}:/data/db --privileged=true mongoclient/mongoclient:latest",
                            admDb.getUsername(), admDb.getPassword(), serverDocker.getIp(), admDb.getPort(), clientMountPath);
                    System.out.println(info2);
                    remoteSshUtil.exec(info2, session);
                    System.out.println(exec);
                    admDb.setContainerId(exec.replace("\n", ""));
                    admDb.setInstallTime(new Date());
                    this.updateById(admDb);
                    sendMsg("complete", mongoFile.getOriginalFilename(), Long.parseLong(id));
                    sendMsg("complete", mongoclientFile.getOriginalFilename(), Long.parseLong(id));
                    remoteSshUtil.close(session);
                } catch (Exception e) {
                    e.printStackTrace();
                    alertFailMsg(e.getMessage());
                } finally {
                    mainLatch.countDown();
                }
            });
        }
        try {
            mainLatch.await();
            System.out.println("mongo全部安装完毕");
            alertSuccessMsg("completeAll");
        } catch (InterruptedException e) {
            log.error(e.getMessage());
        }
    }

    @Override
    public void installRedis(String ids, String tempPath, MultipartFile redisFile) {
        long fileSize = redisFile.getSize();
        String[] split = ids.split(",");
        CountDownLatch mainLatch = new CountDownLatch(split.length);
        for (String id : split) {
            threadPoolTaskExecutor.execute(() -> {
                //上传包
                try {
                    AdmDb admDb = admDbMapper.selectById(id);
                    if (admDb.getDockerId() == null) {
                        return;
                    }
                    AdmDocker admDocker = admDockerMapper.selectById(admDb.getDockerId());
                    Server serverDocker = serverService.getServerById(admDb.getServerId());
                    Session session = remoteSshUtil.connect(serverDocker);
                    System.out.println("开始上传redis镜像文件");
                    //关闭防火墙
                    remoteSshUtil.exec(AutoConstants.DISABLE_FIREWALLD, session);
                    remoteSshUtil.exec(AutoConstants.STOP_FIREWALLD, session);
                    remoteSshUtil.exec(AutoConstants.AUTHORIZATION_FOLDER + tempPath, session);
                    CountDownLatch mainLatch2 = new CountDownLatch(1);
                    threadPoolTaskExecutor.execute(() -> {
                        try {
                            remoteSshUtil.putFile(session, redisFile, tempPath, fileSize, Long.parseLong(id), "dbInstall", serverDocker.getIp());
                        } catch (Exception e) {
                            throw new ServiceException(e.getMessage());
                        } finally {
                            mainLatch2.countDown();
                        }
                    });
                    mainLatch2.await();
                    sendMsg("installing", redisFile.getOriginalFilename(), Long.parseLong(id));
                    String mountPath = admDb.getMountPath();
                    String configLocalPath = baseRedisLocalPath + "/" + admDb.getId() + "/redis.conf";
                    remoteSshUtil.exec(StringUtils.format("mkdir -p {} {}/data", mountPath, mountPath), session);
                    HashMap<String, Object> map = new HashMap<>();
                    map.put("password", admDb.getPassword());
                    map.put("port", admDb.getPort().toString());
                    FileUtils.generateFileByTemplate("redis.ftl", configLocalPath, baseRedisLocalPath + "/" + admDb.getId(), map);
                    remoteSshUtil.putFile(session, configLocalPath, mountPath);
                    remoteSshUtil.exec(AutoConstants.AUTHORIZATION_FOLDER + mountPath, session);
                    DockerClient dockerClient = dockerUtil.getDockerClientByDocker(SpringUtils.getBean(AdmDockerServiceImpl.class).convertToVo(admDocker));
                    dockerUtil.delContainer(dockerClient, "redis");
                    dockerUtil.close(dockerClient);
                    sendMsg("loading", redisFile.getOriginalFilename(), Long.parseLong(id));
                    //加载到镜像
                    remoteSshUtil.exec(StringUtils.format("docker load -i {}/{}", tempPath, redisFile.getOriginalFilename()), session);
                    //安装mysql
                    String info = StringUtils.format("docker run  -d --restart=always --privileged=true --network=host --log-opt max-size=100m --log-opt max-file=2  --name redis \\\n" +
                            "-v /etc/localtime:/etc/localtime \\\n" +
                            "-v {}/redis.conf:/etc/redis/redis.conf -v {}/data/:/data redis \\\n" +
                            "redis-server /etc/redis/redis.conf  --appendonly yes  --requirepass {}", mountPath, mountPath, admDb.getPassword());
                    System.out.println(info);
                    String exec = remoteSshUtil.exec(info, session);
                    System.out.println(exec);
                    admDb.setContainerId(exec.replace("\n", ""));
                    admDb.setInstallTime(new Date());
                    this.updateById(admDb);
                    sendMsg("complete", redisFile.getOriginalFilename(), Long.parseLong(id));
                    remoteSshUtil.close(session);
                } catch (Exception e) {
                    e.printStackTrace();
                    alertFailMsg(e.getMessage());
                } finally {
                    mainLatch.countDown();
                }
            });
        }
        try {
            mainLatch.await();
            System.out.println("redis全部安装完毕");
            alertSuccessMsg("completeAll");
        } catch (InterruptedException e) {
            log.error(e.getMessage());
        }
    }

    @Override
    public void executeSql(String dbId, String databaseName, Long projectId) {
        AdmDb admDb = this.getById(dbId);
        Server server = serverService.getServerByDockerId(admDb.getDockerId());
        AdmProject admProject = admProjectMapper.selectById(projectId);
        String path = StringUtils.format(AutoConstants.SQL_PATH, admProject.getGitlabProjectName());
        List<File> fileList = FileUtils.getAllFile(path);
        if (CollectionUtil.isEmpty(fileList)) {
            log.warn("路径：{} 无sql文件....", path);
            return;
        }
        String className = AutoConstants.DRIVER_NAME;
        String dbUrl = StringUtils.format("jdbc:mysql://{}:{}/{}?useUnicode=true&allowMultiQueries=true&characterEncoding=UTF-8&" +
                "serverTimezone=GMT%2B8&autoReconnect=true&failOverReadOnly=false&useSSL=false", server.getIp(), admDb.getPort(), databaseName);
        String dbUsername = admDb.getUsername();
        String dbPassword = admDb.getPassword();
        try {
            Class.forName(className);
            Connection conn = DriverManager.getConnection(dbUrl, dbUsername, dbPassword);
            ScriptRunner runner = new ScriptRunner(conn);
            runner.setAutoCommit(true);
            for (File file : fileList) {
                if (file.getName().endsWith(".sql")) {
                    String fullName = StringUtils.format("{}/{}", path, file.getName());
                    runner.setFullLineDelimiter(false);
                    //语句结束符号设置
                    runner.setDelimiter(";");
                    //日志数据输出，这样就不会输出过程
                    runner.setLogWriter(null);
                    //这个设置为false是为了能够识别plsql的代码块，否则无法执行pl/sql的脚本，只能执行正常的sql语句。
                    runner.setEscapeProcessing(false);
                    //这个是为了读取脚本所有语句，否则会按行读取进行执行，导致脚本解析错误，无法正常执行分行的begin end代码块。
                    runner.setSendFullScript(true);
                    runner.setAutoCommit(true);
                    runner.setStopOnError(true);
                    runner.runScript(new InputStreamReader(Files.newInputStream(Paths.get(fullName)), StandardCharsets.UTF_8));
                    log.info(StringUtils.format("{}执行成功", fullName));
                    String copyPath = StringUtils.format("{}/{}", path, DateUtils.getDate());
                    FileUtils.copyFile(fullName, copyPath, "executed_" + file.getName());
                    file.delete();
                }
            }
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException(e.getMessage());
        }
    }

    @Override
    public List<AdmDbVo> getByType(String type,String name) {
        List<AdmDb> list = this.list(Wrappers.lambdaQuery(AdmDb.class).eq(AdmDb::getDbType, type).like(StringUtils.isNotEmpty(name), AdmDb::getName, name));
        List<AdmDbVo> voList = BeanUtils.copyList(list, AdmDbVo.class);
        List<Server> serverList = serverService.getAll();
        voList.forEach(vo -> {
            Server server = serverList.stream().filter(s -> s.getId().equals(vo.getServerId())).findFirst().orElse(null);
            vo.setIp(server.getIp());
        });
        return voList;
    }

    @Override
    public List<AdmDb> getAll() {
        if (cacheUtils.hasKey("getAllAdmDb")) {
            return cacheUtils.getCacheObject("getAllAdmDb");
        }else {
            List<AdmDb> list = admDbMapper.selectList(null);
            cacheUtils.setCacheObject("getAllAdmDb", list,60*60*1000*24);
            return list;
        }
    }

    /**
     * 创建mysql
     *
     * @param admDb
     * @throws Exception
     */
    private void creatMysqlUser(AdmDb admDb) throws Exception {
        int ColumnCount;
        Connection conn = getRootMysqlConnection(admDb);
        conn.prepareStatement(StringUtils.format("create user '{}'@'%' identified with mysql_native_password by '{}';", admDb.getUsername(), admDb.getPassword())).execute();
        conn.prepareStatement(StringUtils.format("GRANT ALL ON *.* TO '{}'@'%';", admDb.getUsername())).execute();
        conn.prepareStatement("FLUSH PRIVILEGES;").execute();
        PreparedStatement ps = conn.prepareStatement(StringUtils.format("select user,host from user;"));
        ResultSet rs = ps.executeQuery();
        List list = new ArrayList<String>();
        ResultSetMetaData rsmd = rs.getMetaData();
        while (rs.next()) {
            ColumnCount = rsmd.getColumnCount();
            Map<String, Object> rowData = new HashMap<>();
            for (int i = 1; i <= ColumnCount; i++) {
                rowData.put(rsmd.getColumnName(i), rs.getObject(i));
            }
            //将ResultSet结果集写入list
            list.add(rowData);
            System.out.println(rowData);
        }
        ps.close();
        conn.close();
    }
    private void creatPostgresUser(AdmDb admDb) throws Exception {
        Connection conn = getDefaultPostgresConnection(admDb);
        conn.prepareStatement(StringUtils.format("CREATE USER {} WITH PASSWORD '{}';", admDb.getUsername(), admDb.getPassword())).execute();
        conn.prepareStatement(StringUtils.format("GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO {};", admDb.getUsername())).execute();
        conn.prepareStatement(StringUtils.format("ALTER USER {} WITH CREATEDB;", admDb.getUsername())).execute();
        conn.prepareStatement("SELECT pg_reload_conf();").execute();
        conn.close();
    }

    public void updateMysqlPassword(AdmDb dbOld, AdmDb admDb) throws Exception {
        Connection conn = getMysqlConnection(dbOld);
        String sql = StringUtils.format("alter user '{}'@'%' identified by '{}';", admDb.getUsername(), admDb.getPassword());
        System.out.println(sql);
        conn.prepareStatement(sql).execute();
        conn.prepareStatement("FLUSH PRIVILEGES;").execute();
        conn.close();
    }

    @Override
    public Connection getMysqlConnection(AdmDb admDb) throws Exception {
        Server server = serverService.getServerById(admDb.getServerId());
        Class.forName("com.mysql.cj.jdbc.Driver");
        Connection connection = DriverManager.getConnection(StringUtils.format("jdbc:mysql://{}:{}/mysql?useUnicode=true&allowMultiQueries=true" +
                "&characterEncoding=UTF-8&serverTimezone=GMT%2B8&autoReconnect=true&failOverReadOnly=false&useSSL=false&allowPublicKeyRetrieval=true", server.getIp(), admDb.getPort()), admDb.getUsername(), admDb.getPassword());
        return connection;
    }

    public Connection getRootMysqlConnection(AdmDb admDb) throws Exception {
        Server server = serverService.getServerById(admDb.getServerId());
        Class.forName("com.mysql.cj.jdbc.Driver");
        Connection connection = DriverManager.getConnection(StringUtils.format("jdbc:mysql://{}:{}/mysql?useUnicode=true&allowMultiQueries=true" +
                "&characterEncoding=UTF-8&serverTimezone=GMT%2B8&autoReconnect=true&failOverReadOnly=false&useSSL=false&allowPublicKeyRetrieval=true", server.getIp(), admDb.getPort()), "root", admDb.getPassword());
        return connection;
    }
    public Connection getDefaultPostgresConnection(AdmDb admDb) throws Exception {
        Server server = serverService.getServerById(admDb.getServerId());
        Class.forName("org.postgresql.Driver");
        Connection connection = DriverManager.getConnection(StringUtils.format("jdbc:postgresql://{}:{}/postgres?useUnicode=true&allowMultiQueries=true" +
                "&characterEncoding=UTF-8&serverTimezone=GMT%2B8&autoReconnect=true&failOverReadOnly=false&useSSL=false", server.getIp(), admDb.getPort()), "postgres", admDb.getPassword());
        return connection;
    }
    @Override
    public Connection getPostgresConnection(AdmDb admDb) throws Exception {
        Server server = serverService.getServerById(admDb.getServerId());
        Class.forName("org.postgresql.Driver");
        Connection connection = DriverManager.getConnection(StringUtils.format("jdbc:postgresql://{}:{}/postgres?useUnicode=true&allowMultiQueries=true" +
                "&characterEncoding=UTF-8&serverTimezone=GMT%2B8&autoReconnect=true&failOverReadOnly=false&useSSL=false", server.getIp(), admDb.getPort()), admDb.getUsername(), admDb.getPassword());
        return connection;
    }

    private void sendMsg(String status, String name, Long id) {
        websocketEndPoint.send(WsSendDto.builder().type(0).table("dbInstall").status(status).name(name).id(id).build());
    }

    /**
     * 弹窗提示
     *
     * @param data
     */
    private void alertSuccessMsg(String data) {
        websocketEndPoint.send(WsSendDto.builder().type(2).table("dbInstall").data(data).build());
    }

    /**
     * 弹窗提示
     *
     * @param data
     */
    private void alertFailMsg(String data) {
        websocketEndPoint.send(WsSendDto.builder().type(3).table("dbInstall").data(data).build());
    }
}
